package com.youlu.campus.service.base;

import com.youlu.campus.base.base.SimpleUserInfo;
import com.youlu.campus.base.base.UserInfo;

import com.youlu.campus.common.utils.TimeUtils;
import com.youlu.campus.entity.OrderNoIdPO;
import com.youlu.campus.entity.UserPO;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 基础实现类
 *
 * @author: zhugz
 * @date: 2020/10/20 14:25
 */
@Slf4j
public abstract class BaseService {

    @Value("${sys.qq.appId}")
    protected String appId;
    /**
     * 默认租户ID
     */
    @Value("${campus.defaultTenantId:5fc5e0c6b8016b1f865aa02f}")
    protected String defaultTenantId;

    @Autowired
    protected MapperFacade mapperFacade;

    @Autowired
    protected MongoTemplate mongoTemplate;

    @Autowired
    protected StringRedisTemplate redisTemplate;

    @Autowired
    protected LockService lockService;

    final private static String orderNoPreKey = "luyou.campus.order-no";

    final private static String orderNoEPreKey = "campus:order-no";

    private static Long orderNoExpireTime = 365 * 24 * 3600 * 1000L;


    public <T> List<T> list(String key, Object value, Class<T> t) {
        Query query = new Query();
        query.addCriteria(Criteria.where(key).is(value));
        return mongoTemplate.find(query, t);
    }

    public <T> T find(String key, Object value, Class<T> t) {
        Query query = new Query();
        query.addCriteria(Criteria.where(key).is(value));
        return mongoTemplate.findOne(query, t);
    }

    protected SimpleUserInfo handlerUserInfo(UserPO user) {
        SimpleUserInfo userInfo = new SimpleUserInfo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setUserId(user.getId());
        return userInfo;
    }

    protected UserInfo getUserInfo(UserPO user) {
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setUserId(user.getId());
        return userInfo;
    }

    protected Map<String, UserPO> getUserInfo(List<String> userIds) {
        Map<String, UserPO> userMap = new HashMap<>();
        Query query = new Query(Criteria.where("id").in(userIds));
        List<UserPO> userList = mongoTemplate.find(query, UserPO.class);
        for (UserPO user : userList) {
            userMap.put(user.getId(), user);
        }
        return userMap;
    }

    public boolean resubmit(long expireSeconds, Object... args) {
        StringBuilder builder = new StringBuilder("gjy");
        for (Object arg : args) {
            if (arg == null) {
                builder.append("null");
            } else {
                builder.append(arg.toString());
            }
        }
        //获取md5值
        String key = DigestUtils.md5Hex(builder.toString());
        if (redisTemplate.opsForValue().setIfAbsent(key, key, expireSeconds, TimeUnit.SECONDS)) {
            return false;
        }
        log.info("resubmit {}", builder.toString());
        return true;
    }

    /**
     * 生成订单编号
     */
    public String generateOrderNo(String itemNo) {
        String orderNo = this.generateCreNo();
        for (int i = 0; i < 1000; i++) {
            log.info(":>>> 生成订单编号:{}", i);
            if (checkOrderNo(orderNo)) {
                break;
            } else {
                orderNo = this.generateCreNo();
            }
        }
        log.info(":>>> 生成的订单编号为:{},{}", itemNo, orderNo);
        return orderNo;
    }

    /**
     * 校验订单编号
     *
     * @param orderNo
     * @return
     */
    private boolean checkOrderNo(String orderNo) {
        try {
            OrderNoIdPO orderNoIdPO = new OrderNoIdPO();
            orderNoIdPO.setOrderNo(orderNo);
            orderNoIdPO.setCreatedTime(new Date());
            mongoTemplate.insert(orderNoIdPO);
            return true;
        } catch (Exception e) {
            log.error(":>>> 生成订单编号异常:{}", e);
            return false;

        }
    }

    private String generateCreNo() {

        RedisAtomicLong entityIdCounter = new RedisAtomicLong(orderNoPreKey, redisTemplate.getConnectionFactory());
        Long increment = entityIdCounter.getAndIncrement();
        log.info(":>>> 自增的长度为:{}", increment);
        if ((null == increment || increment.longValue() == 0)) {
            //初始设置过期时间
            entityIdCounter.expire(orderNoExpireTime, TimeUnit.SECONDS);
        }
        Integer r = (int) (1 + Math.random() * (100 - 1 + 1));
        log.info(":>>> 订单编号随机数:{}", r);
        // goodsCode对应证书编码,yyyyMMdd
        String orderNo =
                TimeUtils.formatDate(new Date(), "yyyyMMdd") + "" + r + "" + entityIdCounter;
        return orderNo;
    }

    /**
     * 生成订单编号
     */
    public String generateEOrderNo(String itemNo) {

        RedisAtomicLong entityIdCounter = new RedisAtomicLong(orderNoEPreKey, redisTemplate.getConnectionFactory());
        Long increment = entityIdCounter.getAndIncrement();
        log.info(":>>> 自增的长度为:{}", increment);

        if ((null == increment || increment.longValue() == 0)) {
            //初始设置过期时间
            entityIdCounter.expire(orderNoExpireTime, TimeUnit.SECONDS);
        }

        // goodsCode对应证书编码
        String orderNo =
                TimeUtils.formatDate(new Date(), "yyyyMMddHHmmssSSS") + (long) (Math.random() * (1000)) + "-" + entityIdCounter;
        log.info(":>>> 生成的订单编号为:{},{}", itemNo, orderNo);
        return itemNo + orderNo;
    }
}
